#include "Employee.h"
#include "HttpGetRequest.h"
#include "HttpPutRequest.h"
#include "Job.h"
#include "Effect.h"

#include <sstream>
#include "cv.h"
#include "highgui.h"
#include "Poco/Thread.h"
#include "boost/smart_ptr.hpp"
#include "Poco/Exception.h"

using Poco::Thread;
using Poco::Exception;
using cv::imdecode;
using cv::imencode;
using cv::Mat;
using boost::shared_ptr;

using namespace std;

Employee::Employee(const string& serverAddress, unsigned short port)
{
    this->serverAddress = serverAddress;
    this->port = port;
}

void Employee::run()
{
    // The main employee loop, on server error exception will get thrown
    // and the loop will be over (gracefully)
    while(true)
    {
        // Try to get a new job
        cout << "Sending GET_NEW_JOB_URL request...";
        HttpGetRequest httpReq(HttpGetRequest::HTTP_POST, this->serverAddress, this->port, GET_NEW_JOB_URL);
        cout << "Done" << endl;

        if (httpReq.getStatus() == NO_NEW_JOBS)
        {
            cout << "No new jobs, sleeping for some time" << endl;
            Thread::sleep(RETRY_TIMER);
            continue;
        }

        // Parse the xml
        cout << "Parsing job xml...";
        string cXml = httpReq.getResponse();
        Job cJob(httpReq.getResourceId(), cXml);
        cout << "Done" << endl;
        
        
        // Get the resource for the job
        cout << "Sending GET_RESOURCE request...";
        httpReq = HttpGetRequest(HttpGetRequest::HTTP_GET,
                                 this->serverAddress,
                                 this->port,
                                 this->getResourceUrl(cJob.getResourceId(),
                                                      cJob.getInputRepresentation())
                                 );
        cout << "DONE" << endl;
        
        // Try to decode the image
        Mat sourceMat = imdecode( (Mat)httpReq.getResponseVector(), -1);
        if(sourceMat.empty())
        {
            ostringstream exceptionMsg;  
            exceptionMsg << "Employee::run failed loading resourceID: " << 
                         cJob.getResourceId() << ",representationID: " << cJob.getInputRepresentation();
            throw Exception(exceptionMsg.str());
        }
        
        
        // Run the given effects on the downloaded resource
        Mat outputMat = sourceMat;
        vector< shared_ptr <Effect> > effects = cJob.getEffects();
        for(unsigned int i=0;i<effects.size();i++)
        {
            shared_ptr <Effect> cEffect = effects[i];
            outputMat = cEffect->run(outputMat);
        }
        
        // Send the response
        vector <unsigned char> outputEncoded;
        imencode(OUTPUT_FORMAT,outputMat, outputEncoded);
        cout << "Sending PUT_RESPONSE...";
        HttpPutRequest httpPut = HttpPutRequest(this->serverAddress,
                                 this->port,
                                 this->getResourceUrl(cJob.getResourceId(),
                                                      cJob.getOutputRepresentation()),
                                 outputEncoded
                                 );
        cout << "DONE" << endl;
    }
}

string Employee::getResourceUrl(int resourceId, int representationId)
{
    ostringstream result;  
    result << "/photos/" << resourceId << "?rep=" << representationId;
    return result.str();
}